﻿// ****************************************************************
// Copyright 2012, Stephan Burguchev
// e-mail: me@sburg.net
// ****************************************************************
// *
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Serialization;
using Updater.Common;
using Updater.Updates;
using Updater.Utils;

namespace Updater
{
    internal static class Program
    {
        public static int Main(string[] args)
        {
            MultiPlatformDllLoader.Enable = true;

#if DEBUG
            // Debugger.Break();
#endif
            string updaterFilename = Path.GetFileNameWithoutExtension(PathHelper.ExecutablePath);

            if (args.Length != 1)
            {
                string message = "Invalid arguments. You must pass an pipe name as a single and required argument.";
                Console.WriteLine(message);
                MessageBox.Show(message, updaterFilename, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return 1;
            }

            InterProcessData ipd = null;
            string appFilename;
            try
            {
                var ms = new MemoryStream();
                NamedPipeHelper.ReadData(args[0], ms);
                ms.Seek(0, SeekOrigin.Begin);
                ipd = InterProcessData.Deserialize(ms);

                appFilename = Path.Combine(ipd.Configuration.ApplicationDirectory, ipd.Configuration.ApplicationFilename);
                string processName = Path.GetFileNameWithoutExtension(ipd.Configuration.ApplicationFilename);

                if (!File.Exists(appFilename))
                {
                    throw new FileNotFoundException("The application executable does not exist.");
                }

                string fullname = new FileInfo(appFilename).FullName;
                List<Process> processesToWait = Process.GetProcessesByName(processName).Where(
                    p => fullname == new FileInfo(p.MainModule.FileName).FullName).ToList();
                foreach (Process process in processesToWait)
                {
                    process.WaitForExit();
                }

                foreach (UpdateInformation updateInformation in ipd.UpdatesToApply)
                {
                    var update = (IUpdate)Activator.CreateInstance(updateInformation.UpdateType);
                    update.Configuration = ipd.Configuration;
                    update.Information = updateInformation;
                    update.Apply();
                }

                Console.WriteLine("The updates have been successfully installed.");
            }
            catch (Exception ex)
            {
                string message = string.Format("Unable to apply an update. {0}", ex.GetFullMessage());
                Console.WriteLine(message);
                if (ipd != null)
                {
                    createUpdateLog(ipd, UpdateLog.CreateErrorLog(message, ex.ToString()));
                }

                MessageBox.Show(message, updaterFilename, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return 1;
            }

            if (ipd.RestartApplication)
            {
                try
                {
                    Process.Start(appFilename);
                }
                catch (Exception ex)
                {
                    string message = string.Format("Unable to start an updated application. {0}", ex.GetFullMessage());
                    Console.WriteLine(message);
                    createUpdateLog(ipd, UpdateLog.CreateErrorLog(message, ex.ToString()));
                    MessageBox.Show(message, updaterFilename, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return 1;
                }
            }

            createUpdateLog(ipd, UpdateLog.CreateSuccessLog(ipd.UpdatesToApply, ipd.ChangeLog));
            return 0;
        }

        private static void createUpdateLog(InterProcessData ipd, UpdateLog updateLog)
        {
            using (FileStream stream = File.Create(Path.Combine(ipd.Configuration.UpdaterCacheDirectory, "updateLog.xml")))
            {
                var serializer = new XmlSerializer(typeof(UpdateLog));
                serializer.Serialize(stream, updateLog);
            }
        }
    }
}
